﻿using LPP.Repository;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Aliyun.Acs.Core.Exceptions;
using Microsoft.Extensions.Logging;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Core;
using Aliyun.Acs.Dysmsapi.Model.V20170525;
using Microsoft.Extensions.Caching.Memory;
using System.Text.Json;
using LPP.Core.Aliyun;
using LPP.Entity;

namespace LPP.Service.SmsService
{
    public class SmsService
    {
        private readonly LPP.Repository.SmsVerificationRepository _smsVerificationRepository;
        private readonly IConfiguration _configuration;
        private readonly ILogger<SmsService> _logger;
        private readonly IMemoryCache _cache;
        private readonly AliyunSmsOptions _aliyunOptions;
        private readonly IAcsClient _acsClient;

        private const int CODE_LENGTH = 6;
        private const int CODE_EXPIRY_MINUTES = 5;
        private const int SEND_INTERVAL_SECONDS = 60;

        public SmsService(
            LPP.Repository.SmsVerificationRepository smsVerificationRepository,
            IConfiguration configuration,
            ILogger<SmsService> logger,
            IMemoryCache cache,
            IOptions<AliyunSmsOptions> aliyunOptions)
        {
            _smsVerificationRepository = smsVerificationRepository;
            _configuration = configuration;
            _logger = logger;
            _cache = cache;
            _aliyunOptions = aliyunOptions.Value;

            // 初始化阿里云客户端
            var profile = DefaultProfile.GetProfile(
                "cn-hangzhou",  // regionId
                _aliyunOptions.AccessKeyId,
                _aliyunOptions.AccessKeySecret
            );

            // 设置域名
            DefaultProfile.AddEndpoint(
                "cn-hangzhou",    // regionId
                "cn-hangzhou",    // region
                "Dysmsapi",       // product
                "dysmsapi.aliyuncs.com"  // domain
            );

            _acsClient = new DefaultAcsClient(profile);
        }

        /// <summary>
        /// 发送验证码
        /// </summary>
        public async Task<(bool Success, string Message)> SendVerificationCodeAsync(string phoneNumber)
        {
            try
            {
                // 验证手机号格式
                if (!IsValidPhoneNumber(phoneNumber))
                {
                    return (false, "无效的手机号格式");
                }

                // 检查发送频率
                if (await IsSendingTooFrequentAsync(phoneNumber))
                {
                    return (false, "请求过于频繁，请稍后再试");
                }

                // 生成验证码
                string verificationCode = GenerateVerificationCode();
                
                // 构建短信内容
                string content = $"您的验证码是：{verificationCode}，5分钟内有效。";
                
                // 调用阿里云短信服务发送短信
                await SendSmsAsync(phoneNumber, content);
                
                // 保存验证码到数据库
                await SaveVerificationCodeAsync(phoneNumber, verificationCode);

                _logger.LogInformation("验证码发送成功: {PhoneNumber}", phoneNumber);
                return (true, "验证码发送成功");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "发送验证码失败: {PhoneNumber}", phoneNumber);
                return (false, "发送验证码失败，请稍后重试");
            }
        }

        /// <summary>
        /// 验证验证码
        /// </summary>
        public async Task<(bool Success, string Message)> VerifyCodeAsync(string phoneNumber, string code)
        {
            try
            {
                // 先检查缓存
                string cacheKey = $"sms_code_{phoneNumber}";
                if (_cache.TryGetValue(cacheKey, out string cachedCode))
                {
                    if (code == cachedCode)
                    {
                        await MarkCodeAsUsedAsync(phoneNumber);
                        return (true, "验证成功");
                    }
                }

                // 缓存未命中，检查数据库
                var latestSms = await _smsVerificationRepository.GetLatestByPhoneNumberAsync(phoneNumber);
                if (latestSms == null)
                {
                    return (false, "验证码不存在");
                }

                // 验证码是否已使用
                if (latestSms.IsVerified)
                {
                    return (false, "验证码已使用");
                }

                // 验证码是否匹配
                if (latestSms.Code != code)
                {
                    return (false, "验证码错误");
                }

                // 检查是否过期
                var timeDifference = (DateTime.UtcNow - latestSms.CreatedAt).TotalMinutes;
                if (timeDifference > CODE_EXPIRY_MINUTES)
                {
                    return (false, "验证码已过期");
                }

                // 标记验证码为已使用
                await MarkCodeAsUsedAsync(phoneNumber);
                return (true, "验证成功");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "验证码验证失败: {PhoneNumber}", phoneNumber);
                return (false, "验证失败，请稍后重试");
            }
        }

        private async Task<(bool Success, string Message)> SendSmsAsync(string phoneNumber, string content)
        {
            try
            {
                var request = new SendSmsRequest
                {
                    PhoneNumbers = phoneNumber,
                    SignName = _aliyunOptions.SignName,
                    TemplateCode = _aliyunOptions.TemplateCode,
                    TemplateParam = JsonSerializer.Serialize(new { code = content })
                };

                // 开发环境直接记录日志
                if (_configuration["ASPNETCORE_ENVIRONMENT"] == "Development")
                {
                    _logger.LogInformation("开发环境 - 手机号: {PhoneNumber}, 验证码: {Code}", phoneNumber, content);
                    return (true, "验证码发送成功");
                }

                var response = _acsClient.GetAcsResponse(request);
                if (response.Code == "OK")
                {
                    return (true, "验证码发送成功");
                }

                _logger.LogError("短信发送失败: {Code}, {Message}", response.Code, response.Message);
                return (false, "短信发送失败，请稍后重试");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "发送短信时发生错误");
                return (false, "发送失败，请稍后重试");
            }
        }

        private async Task MarkCodeAsUsedAsync(string phoneNumber)
        {
            try
            {
                var smsVerification = await _smsVerificationRepository.GetLatestByPhoneNumberAsync(phoneNumber);
                if (smsVerification != null)
                {
                    smsVerification.IsVerified = true;
                    await _smsVerificationRepository.UpdateAsync(smsVerification);
                }

                // 从缓存中移除
                string cacheKey = $"sms_code_{phoneNumber}";
                _cache.Remove(cacheKey);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "标记验证码使用状态失败: {PhoneNumber}", phoneNumber);
            }
        }

        private bool IsValidPhoneNumber(string phoneNumber)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(phoneNumber, @"^1[3-9]\d{9}$");
        }

        private string GenerateVerificationCode()
        {
            Random random = new Random();
            return random.Next(100000, 999999).ToString();
        }

        private void StoreSmsCode(string phoneNumber, string code)
        {
            string codeKey = $"sms_code_{phoneNumber}";
            string lastSendTimeKey = $"sms_last_send_{phoneNumber}";

            var cacheOptions = new MemoryCacheEntryOptions()
                .SetAbsoluteExpiration(TimeSpan.FromMinutes(CODE_EXPIRY_MINUTES));

            _cache.Set(codeKey, code, cacheOptions);
            _cache.Set(lastSendTimeKey, DateTime.Now, cacheOptions);
        }

        public async Task<bool> IsSendingTooFrequentAsync(string phoneNumber)
        {
            string lastSendTimeKey = $"sms_last_send_{phoneNumber}";
            if (_cache.TryGetValue(lastSendTimeKey, out DateTime lastSendTime))
            {
                return (DateTime.Now - lastSendTime).TotalSeconds < SEND_INTERVAL_SECONDS;
            }

            var latestSms = await _smsVerificationRepository.GetLatestByPhoneNumberAsync(phoneNumber);
            if (latestSms == null) return false;

            var timeDifference = (DateTime.UtcNow - latestSms.CreatedAt).TotalSeconds;
            return timeDifference < SEND_INTERVAL_SECONDS;
        }

        private async Task SaveVerificationCodeAsync(string phoneNumber, string code)
        {
            var smsVerification = new SmsVerification
            {
                PhoneNumber = phoneNumber,
                Code = code,
                CreatedAt = DateTime.UtcNow,
                IsVerified = false
            };

            await _smsVerificationRepository.AddAsync(smsVerification);
            StoreSmsCode(phoneNumber, code);
        }
    }
}









